home *** CD-ROM | disk | FTP | other *** search
/ Mission 3 / Mission 3.zip / Mission 3.iso / spiele / thrust / source / thrust.mod < prev    next >
Text File  |  1996-10-16  |  39KB  |  1,395 lines

  1. MODULE Thrust;
  2.  
  3. IMPORT Math, IO, Strings, NumStr, File,
  4.  
  5.        VC := VDIControl, VA := VDIAttributes, VO := VDIOutput,
  6.        VR := VDIRaster, VI := VDIInquiry,
  7.  
  8.        GemApp, Graf, Evnt, Wind, Form, Menus, Rsrc, Dialogs, Objc,
  9.  
  10.        (* Debug, Halt, *)
  11.  
  12.        XBIOS, GEMDOS, SYSTEM, LinkedList, Memory, Sys, Task,
  13.        
  14.        Timer, Image, IWinView, WindowDialog;
  15.  
  16. CONST
  17.  
  18.       (* Resource Datei Indizes für THRUST *)
  19.     
  20.     MENU     =   0;    (* Menuebaum *)
  21.     THRUST   =   3;    (* TITLE in Baum MENU *)
  22.     SPIEL    =   4;    (* TITLE in Baum MENU *)
  23.     INFO     =   7;    (* STRING in Baum MENU *)
  24.     START    =  16;    (* STRING in Baum MENU *)
  25.     ENDE     =  17;    (* STRING in Baum MENU *)
  26.  
  27.     ABOUT    =   1;    (* Formular/Dialog *)
  28.     ICON     =   3;    (* IMAGE in Baum ABOUT *)
  29.  
  30.     BILD     =   2;    (* Formular/Dialog *)
  31.  
  32.  
  33.       (*****************)
  34.  
  35.       pi       = Math.pi;
  36.       twopi    = 2 * pi;
  37.       radtodeg = 57; (* 360 / twopi *)
  38.  
  39.       fixcomma = 4096;  (* 12 Nachkommastellen *)
  40.       nangle   = 360;   (* Anzahl der Winkel (in Grad) *)
  41.       nangle2  = 360 * fixcomma;
  42.  
  43.       abstand     = 40; (* Abstand Raumschiff - Kugel in Pixel *)
  44.       abstand2    = abstand * abstand; (* abstand hoch 2 *)
  45.       ballmasse   = 3; (* Masse der Kugel (relativ zur Raumschiffmasse) *)
  46.       gesamtmasse = ballmasse + 1;
  47.       distball    = abstand DIV gesamtmasse; (* Distanz Schwerpunkt-Ball *)
  48.       distschiff  = abstand * ballmasse DIV gesamtmasse;
  49.       traegschiff = distschiff * distschiff * 1;
  50.       traeggesamt = traegschiff + distball * distball * ballmasse;
  51.  
  52.       NoHit = 0;
  53.       HitBackground = 1;
  54.       HitExit = 2;
  55.       HitShip = 3;
  56.       HitEsc = 4;
  57.  
  58.       WindowTitle = " Thrust 0.5 ";
  59.  
  60. TYPE
  61.  
  62.   Sprite = POINTER TO SpriteDesc;
  63.   SpriteDesc = RECORD
  64.                  shape : ARRAY 32 OF SET; (* maximal 32 x 32 Pixel *)
  65.                  w, h : INTEGER; (* Breite, Höhe *)
  66.                END;
  67.   Bitmap = POINTER TO BitmapDesc;
  68.   BitmapDesc = RECORD
  69.                  width, height, widthSet : INTEGER;
  70.                  size : LONGINT;
  71.                  mem, col : POINTER TO ARRAY MAX(LONGINT) OF SET;
  72.                  visible, update : VR.pxyarray;
  73.                  mfdb : VR.mfdbrec;
  74.                  RandX, RandY : INTEGER; (* ab wo wird gescrollt? *)
  75.                END;
  76.  
  77.   Point = POINTER TO PointDesc;
  78.   PointDesc = RECORD(LinkedList.ElemDesc)
  79.                 x, y : LONGINT; (* Position *)
  80.                 vx, vy : LONGINT; (* Geschwindigkeit *)
  81.                 sx, sy : INTEGER; (* Zeichenkoordinaten *)
  82.                 hit : INTEGER; (* getroffen ? *)
  83.               END;
  84.  
  85.   Explosion = POINTER TO ExplosionDesc;
  86.   ExplosionDesc = RECORD(PointDesc)
  87.                     shape : Sprite;
  88.                     LastShape : LONGINT;
  89.                   END;
  90.  
  91.   Ship = POINTER TO ShipDesc;
  92.   ShipDesc = RECORD(PointDesc)
  93.                beta  : LONGINT; (* Schiffswinkel *)
  94.                sb : INTEGER; (* Zeichen-Winkel *)
  95.                shape, shapet : ARRAY 90 OF Sprite;
  96.                thrust, last : BOOLEAN;
  97.                LastShoot, ShootFreq : LONGINT;
  98.              END;
  99.  
  100.   Ball = POINTER TO BallDesc;
  101.   BallDesc = RECORD(PointDesc);
  102.                shape : Sprite;
  103.                loading : BOOLEAN;
  104.                bx , by : INTEGER; (* Schiffskoordinaten *)
  105.              END;
  106.  
  107.   LoadedShip = POINTER TO LoadedShipDesc;
  108.   LoadedShipDesc = RECORD(ShipDesc)
  109.                      alpha,
  110.                      valpha, valphaconst : LONGINT;
  111.                      mx, my, lx, ly : INTEGER; (* Stange *)
  112.                      ball : Sprite;
  113.                    END;
  114.  
  115.   Defender = POINTER TO DefenderDesc;
  116.   DefenderDesc = RECORD(PointDesc)
  117.                    shape : Sprite;
  118.                    StartAngle, StopAngle : INTEGER;
  119.                    LastShoot, ShootFreq, Range : LONGINT;
  120.                  END;
  121.  
  122.   Level = POINTER TO LevelDesc;
  123.   LevelDesc = RECORD
  124.                 image : ARRAY 128 OF CHAR;
  125.                 corners, ballx, bally, shipx, shipy : INTEGER;
  126.               END;
  127.  
  128.   scTab = ARRAY nangle OF LONGINT;
  129.  
  130.   myViewer = POINTER TO myViewDesc;
  131.   myViewDesc = RECORD(IWinView.IViewDesc);
  132.                END;
  133.  
  134.  
  135. VAR sin, cos : scTab; (* sinus/cosinus Tabelle *)
  136.  
  137.     Station : INTEGER;
  138.     Workout : VC.workout;
  139.     Color : BOOLEAN; (* Farbbildschirm *)
  140.     win : myViewer; (* Ausgabefenster *)
  141.     InfoDialog : WindowDialog.Dialog;
  142.     menu : Menus.Menu;
  143.  
  144.     Screen : VR.mfdbrec;
  145.     VScreen : Bitmap;
  146.     Collision : BOOLEAN;
  147.  
  148.     objects : LinkedList.Ptr; (* aktuelle Objekte *)
  149.     nobj, ende : INTEGER;
  150.     debug : BOOLEAN;
  151.  
  152.     myShip : Ship;
  153.     myBall : Ball;
  154.     myLoadedShip : LoadedShip;
  155.     myLevel : Level;
  156.     myDefender : Defender;
  157.  
  158.     dt : LONGINT; (* Zeitschritt *)
  159.     AccStep, BetaStep, GravStep : LONGINT; (* Schrittweite für Beschl. u. Winkel *)
  160.     Gravitation : BOOLEAN;
  161.     HitCount : INTEGER;
  162.     
  163. (* Allgemeine Hilfsprozeduren *******************************************)
  164.  
  165. PROCEDURE InitTables ();
  166. VAR i, l : LONGINT; r : REAL;
  167. BEGIN
  168.   FOR i := 0 TO nangle - 1 DO
  169.     r := i;
  170.     sin[i] := ENTIER(Math.sin(r * 0.0174533) * fixcomma);
  171.     cos[i] := ENTIER(Math.cos(r * 0.0174533) * fixcomma);
  172.   END;
  173. (*
  174.   IO.WriteString("InitTables finished!"); IO.WriteLn;
  175. *)
  176. (*
  177.   l := SIZE(scTab);
  178.   IF File.LoadTo("SINUS.TAB", SYSTEM.ADR(sin), l) THEN
  179.  
  180.  
  181.     IO.WriteString("SINUS.TAB written!"); IO.WriteLn();
  182.   END;
  183.   IF File.LoadTo("COSIN.TAB", SYSTEM.ADR(cos), l) THEN
  184.     IO.WriteString("COSIN.TAB written!"); IO.WriteLn();
  185.   END;
  186. *)
  187.   Screen.Addr := 0; (* Bildschirm *)
  188.   HitCount := 0;
  189. END InitTables;
  190.  
  191. PROCEDURE ComparePos (str1, str2 : ARRAY OF CHAR; pos : INTEGER) : BOOLEAN;
  192.   VAR
  193.     i : INTEGER;
  194.  BEGIN
  195.   i := 0;
  196.   WHILE str1[i] = str2[pos] DO
  197.     INC(i); INC(pos);
  198.     IF str1[i] = 0X THEN RETURN TRUE END(*IF*);
  199.   END(*WHILE*);
  200.   RETURN FALSE
  201.  END ComparePos;
  202.  
  203. PROCEDURE I (s : ARRAY OF CHAR; a,b,c,d : LONGINT; Wait : BOOLEAN);
  204. BEGIN
  205.   IO.WriteString(s);
  206.   IO.WriteInt(a); IO.WriteString(" ");
  207.   IO.WriteInt(b); IO.WriteString(" ");
  208.   IO.WriteInt(c); IO.WriteString(" ");
  209.   IO.WriteInt(d); IO.WriteString(" ");
  210.   IO.WriteLn;
  211. END I;
  212.  
  213. PROCEDURE R (s : ARRAY OF CHAR; r1,r2,r3,r4 : REAL; Wait : BOOLEAN);
  214. VAR ch : CHAR;
  215. BEGIN
  216.   IO.WriteString(s);
  217.   IO.WriteReal(r1, 2, 0, 10, ' ');
  218.   IO.WriteReal(r2, 2, 0, 10, ' ');
  219.   IO.WriteReal(r3, 2, 0, 10, ' ');
  220.   IO.WriteReal(r4, 2, 0, 10, ' '); IO.WriteLn;
  221.   IF Wait THEN
  222.     ch := IO.ReadChar();
  223.   END;
  224. END R;
  225.  
  226. PROCEDURE M (name : ARRAY OF CHAR; m : VR.mfdbrec);
  227. VAR ch : CHAR;
  228. BEGIN
  229.   IO.WriteString(name); IO.WriteLn;
  230.   IO.WriteString("MFDB.Addr = "); IO.WriteInt(m.Addr); IO.WriteLn;
  231.   IO.WriteString("     Width = "); IO.WriteInt(m.Width); IO.WriteLn;
  232.   IO.WriteString("     Height = "); IO.WriteInt(m.Height); IO.WriteLn;
  233.   IO.WriteString("     WidthW = "); IO.WriteInt(m.WidthW); IO.WriteLn;
  234.   IO.WriteString("     Format = "); IO.WriteInt(m.Format); IO.WriteLn;
  235.   IO.WriteString("     Planes = "); IO.WriteInt(m.Planes); IO.WriteLn;
  236. END M;
  237.  
  238.  
  239. PROCEDURE B (s : ARRAY OF CHAR; x : SET; LF : BOOLEAN);
  240. VAR i : INTEGER;
  241. BEGIN
  242.   IO.WriteString(s);
  243.   FOR i := 31 TO 0 BY -1 DO
  244.     IF i IN x THEN
  245.       IO.WriteChar("o");
  246.     ELSE
  247.       IO.WriteChar(".");
  248.     END;
  249.   END;
  250.   IF LF THEN
  251.     IO.WriteLn();
  252.   END;
  253. END B;
  254.  
  255. (* Prozeduren auf Levels ************************************************)
  256.  
  257. PROCEDURE (l : Level) Init ();
  258. VAR length, count : LONGINT;
  259.     start : POINTER TO ARRAY OF CHAR;
  260.     t : ARRAY 255 OF CHAR;
  261.     Comment : INTEGER;
  262.     b : BOOLEAN;
  263.     
  264.   PROCEDURE GetToken (VAR s : ARRAY OF CHAR) : BOOLEAN;
  265.   VAR i : INTEGER;
  266.   BEGIN
  267.     WHILE (count < length) AND (start^[count] <= " ") DO 
  268.       INC(count);
  269.     END;
  270.     IF count >= length THEN RETURN FALSE END;
  271.     i := 0;
  272.     WHILE (count < length) AND (start^[count] > " ") DO 
  273.       s[i] := start^[count]; INC(i); INC(count);
  274.     END;
  275.     s[i] := CHR(0);
  276.     RETURN TRUE;
  277.   END GetToken;
  278.  
  279.   PROCEDURE GetNumber () : LONGINT;
  280.   VAR s : ARRAY 128 OF CHAR;
  281.   BEGIN
  282.     IF GetToken(s) THEN
  283.       RETURN NumStr.ToLInt(10, s);
  284.     END;
  285.     RETURN 0;
  286.   END GetNumber;
  287.  
  288. BEGIN
  289.   l.image := "level.img"; count := 0;
  290.  
  291.   IF ~File.Load ("level1.lev", 0, 1, start, length) THEN
  292.     RETURN 
  293.   END;
  294.  
  295.   NEW(objects); objects.Initialize(); (* Liste intialisieren *)
  296.  
  297.   Comment := 0;
  298.   WHILE GetToken(t) DO
  299.     IF ComparePos(t, "(*", 0) THEN
  300.       INC(Comment);
  301.     ELSIF ComparePos(t, "*)", 0) THEN
  302.       DEC(Comment);
  303.       IF Comment < 0 THEN Comment := 0 END;
  304.     END;
  305.     IF Comment = 0 THEN
  306.       IF ComparePos(t, "image", 0) THEN
  307.         b := GetToken(l.image);
  308.         NEW(VScreen); VScreen.Init(l.image);
  309.       ELSIF ComparePos(t, "ship", 0) THEN
  310.         NEW(myShip);
  311.         myShip.Init (GetNumber() * fixcomma, GetNumber() * fixcomma, 0, 0);
  312.         objects.Insert(myShip);
  313.       ELSIF ComparePos(t, "ball", 0) THEN
  314.         NEW(myBall);
  315.         myBall.Init(GetNumber() * fixcomma, GetNumber() * fixcomma, 0, 0);
  316.         objects.Insert(myBall);
  317.       ELSIF ComparePos(t, "defender", 0) THEN
  318.         NEW(myDefender);
  319.         myDefender.Init(GetNumber() * fixcomma, GetNumber() * fixcomma, 0, 0);
  320.         objects.Insert(myDefender);
  321.       END;
  322.     END;
  323.   END;
  324.   
  325. (*
  326.   NEW(objects); objects.Initialize(); (* Liste intialisieren *)
  327.  
  328.   NEW(VScreen); VScreen.Init("level1.img");
  329.  
  330.   NEW(myShip);
  331.   myShip.Init (550 * fixcomma, 50 * fixcomma, 0, 0);
  332.   objects.Insert(myShip);
  333.  
  334.   NEW(myBall);
  335.   myBall.Init(400 * fixcomma, 700 * fixcomma, 0, 0);
  336.   objects.Insert(myBall);
  337.  
  338.   NEW(myDefender);
  339.   myDefender.Init(100 * fixcomma, 250 * fixcomma, 0, 0);
  340.   objects.Insert(myDefender);
  341.   
  342.   NEW(myDefender);
  343.   myDefender.Init(500 * fixcomma, 550 * fixcomma, 0, 0);
  344.   objects.Insert(myDefender);
  345. *)
  346. END Init;
  347.  
  348. (* Prozeduren auf Sprites ***********************************************)
  349.  
  350. PROCEDURE (s : Sprite) Init (w, h : INTEGER);
  351. VAR i : INTEGER;
  352. BEGIN
  353.   s.w := w; s.h := h;
  354.   FOR i := 0 TO 31 DO
  355.     s.shape[i] := {};
  356.   END;
  357. END Init;
  358.  
  359. PROCEDURE (s : Sprite) Circle (x, y, r : INTEGER);
  360. VAR i, j : INTEGER;
  361. BEGIN
  362.   FOR i := 0 TO 31 DO
  363.     FOR j := 0 TO 31 DO
  364.       IF (i-y)*(i-y) + (j-x)*(j-x) < r*r THEN
  365.         INCL(s.shape[i], 31 - j);
  366.       END;
  367.     END;
  368.   END;
  369. END Circle;
  370.  
  371. PROCEDURE (s : Sprite) Line (x0, y0, x1, y1 : INTEGER);
  372.  
  373. VAR dx, dy, ix, iy, ax, ay, ct, of : INTEGER;
  374. BEGIN
  375.   dx := x1 - x0; dy := y1 - y0;
  376.   ax := 0; ay := 0; ix := 1; iy := 1;
  377.   IF dx < 0 THEN dx := -dx; ix := -1 END;
  378.   IF dy < 0 THEN dy := -dy; iy := -1 END;
  379.   IF dx < dy THEN
  380.     ct := dx; dx := dy; dy := ct; ay := ix; ax := iy; ix := 0; iy := 0;
  381.   END;
  382.   of := dx DIV 2; ct := 0;
  383.  
  384.   WHILE (dx >= ct) DO
  385.     INCL(s.shape[y0], 31 - x0 MOD 32);
  386.     INC(x0, ix); INC(y0, ax); INC (of, dy);
  387.     IF of >= dx THEN
  388.       DEC (of, dx); INC(x0, ay); INC(y0, iy);
  389.     END;
  390.     INC(ct);
  391.   END;
  392. END Line;
  393.  
  394. (* Prozeduren auf einer Bitmap ******************************************)
  395.  
  396. PROCEDURE (b : Bitmap) Init (File : ARRAY OF CHAR);
  397. VAR size, dest, dest2, source : LONGINT;
  398.     i : INTEGER;
  399. BEGIN
  400.   Image.Load(File, b.mfdb);
  401.  
  402.   b.width := b.mfdb.Width; b.height := b.mfdb.Height;
  403.   b.widthSet := (b.width + 31) DIV 32;
  404.   b.size := LONG(b.widthSet) * LONG(b.height);
  405.  
  406.   SYSTEM.NEW (b.mem, b.size * 4);
  407.   SYSTEM.NEW (b.col, b.size * 4);
  408.  
  409.   size := LONG(b.width + 15) DIV 16 * 2;
  410.   FOR i := 0 TO b.height-1 DO
  411.     source := LONG(i) * LONG(b.mfdb.WidthW * 2) + b.mfdb.Addr;
  412.     dest := LONG(i) * LONG(b.widthSet * 4) + SYSTEM.VAL(LONGINT, b.mem);
  413.     dest2 := LONG(i) * LONG(b.widthSet * 4) + SYSTEM.VAL(LONGINT, b.col);
  414.     Memory.Copy(source, dest, size);
  415.     Memory.Copy(source, dest2, size);
  416.   END;
  417.  
  418.   b.mfdb.Addr := SYSTEM.VAL(LONGINT,b.mem);
  419.   b.mfdb.Width := b.width;
  420.   b.mfdb.Height := b.height;
  421.   b.mfdb.WidthW := b.widthSet * 2;
  422.   b.mfdb.Format := 0;
  423.   b.mfdb.Planes := 1;
  424.  
  425.   b.update[0] := 0;
  426.   b.update[1] := 0;
  427.   b.update[2] := b.width - 1;
  428.   b.update[3] := b.height - 1;
  429.  
  430.  
  431.   b.visible[0] := 0; (* sichtbarer Ausschnitt *)
  432.   b.visible[1] := 0;
  433.   b.visible[2] := win.w - 1;
  434.  
  435.   IF b.width < win.w THEN b.visible[2] := b.width - 1 END;
  436.   b.visible[3] := win.h - 1;
  437.   IF b.height < win.h THEN b.visible[3] := b.height - 1 END;
  438.  
  439.  
  440.  
  441.   b.RandX := win.w DIV 4;
  442.   b.RandY := win.h DIV 4;
  443.  
  444. END Init;
  445.  
  446. PROCEDURE (b : Bitmap) Clear ();
  447. VAR i : LONGINT;
  448. BEGIN
  449.   FOR i := 0 TO b.size - 1 DO
  450.     b.mem[i] := {};
  451.     b.col[i] := {};
  452.   END;
  453.   b.update[0] := 0;
  454.   b.update[1] := 0;
  455.   b.update[2] := b.width - 1;
  456.   b.update[3] := b.height - 1;
  457. END Clear;
  458.  
  459. PROCEDURE (b : Bitmap) Point (x, y : INTEGER) : INTEGER;
  460. BEGIN
  461.   IF (x < 0) OR (y < 0) OR
  462.      (x >= b.width) OR (y >= b.height) THEN RETURN HitBackground END;
  463.  
  464.   IF x < b.update[0] THEN b.update[0] := x END;
  465.   IF y < b.update[1] THEN b.update[1] := y END;
  466.   IF x > b.update[2] THEN b.update[2] := x END;
  467.   IF y > b.update[3] THEN b.update[3] := y END;
  468.  
  469.   y := x DIV 32 + y * b.widthSet;
  470.   x := 31 - x MOD 32;
  471.   
  472.   IF x IN b.mem[y] THEN
  473.     EXCL(b.mem[y], x);
  474.     IF x IN b.col[y] THEN
  475.       EXCL(b.col[y], x);
  476.       RETURN HitBackground;
  477.     END;
  478.     RETURN HitShip;
  479.   ELSE
  480.     INCL(b.mem[y], x);
  481.   END;
  482.   RETURN NoHit;
  483. END Point;
  484.  
  485. PROCEDURE (b : Bitmap) GetPoint (x, y : INTEGER) : BOOLEAN;
  486. BEGIN
  487.   IF (x < 0) OR (y < 0) OR
  488.      (x >= b.width) OR (y >= b.height) THEN RETURN FALSE END;
  489.   y := x DIV 32 + y * b.widthSet;
  490.   x := 31 - x MOD 32;
  491.   RETURN x IN b.col[y];
  492. END GetPoint;
  493.  
  494.  
  495. PROCEDURE (b : Bitmap) Sprite (x, y : INTEGER; s : Sprite) : INTEGER;
  496. VAR i, w, h : INTEGER;
  497.     m : SET;
  498.     collision : INTEGER;
  499. BEGIN
  500.   IF (x < 0) OR (y < 0) OR
  501.      (x > b.width - s.w) OR (y > b.height - s.h) THEN
  502.     RETURN HitExit;
  503.   END;
  504.  
  505.   IF x < b.update[0] THEN b.update[0] := x END;
  506.   IF y < b.update[1] THEN b.update[1] := y END;
  507.   IF x + s.w - 1 > b.update[2] THEN b.update[2] := x + s.w - 1 END;
  508.   IF y + s.h - 1 > b.update[3] THEN b.update[3] := y + s.h - 1 END;
  509.  
  510.   collision := NoHit;
  511.   h := x MOD 32; w := x DIV 32 + b.widthSet * y;
  512.   FOR i := 0 TO s.h - 1 DO
  513.  
  514.     m := SYSTEM.VAL(SET, SYSTEM.LSH(SYSTEM.VAL(LONGINT, s.shape[i]), -h));
  515.     IF b.mem[w] * m # {} THEN
  516.       IF b.col[w] * m # {} THEN
  517.         IF collision = NoHit THEN
  518.           collision := HitBackground
  519.         END;
  520.       ELSE
  521.         collision := HitShip;
  522.       END;
  523.     END;
  524.     b.mem[w] := b.mem[w] / m;
  525.  
  526.  
  527.     IF s.w > (32 - h) THEN
  528.       INC(w);
  529.  
  530.  
  531.       m := SYSTEM.VAL(SET, SYSTEM.LSH(SYSTEM.VAL(LONGINT, s.shape[i]), 32-h));
  532.       IF b.mem[w] * m # {} THEN
  533.         IF b.col[w] * m # {} THEN
  534.           IF collision = NoHit THEN
  535.             collision := HitBackground
  536.           END;
  537.         ELSE
  538.           collision := HitShip;
  539.         END;
  540.       END;
  541.       b.mem[w] := b.mem[w] / m;
  542.       INC(w, b.widthSet - 1);
  543.     ELSE
  544.       INC(w, b.widthSet);
  545.     END;
  546.  
  547.   END;
  548.   RETURN collision;
  549. END Sprite;
  550.  
  551.  
  552. PROCEDURE (b : Bitmap) Line (x0, y0, x1, y1 : INTEGER) : INTEGER;
  553. VAR dx, dy, ix, iy, ax, ay, ct, of, xbit, xset : INTEGER;
  554.     collision : INTEGER;
  555. BEGIN
  556.   IF (x0 < 0) OR (y0 < 0) OR (x1 < 0) OR (y1 < 0) THEN
  557.     RETURN HitBackground
  558.   END;
  559.   IF (x0 >= b.width) OR (x1 >= b.width) OR
  560.      (y0 >= b.height) OR (y1 >= b.height) THEN
  561.     RETURN HitBackground;
  562.   END;
  563.  
  564.   (* Update Rechteck aktualisieren *)
  565.   IF x0 > x1 THEN ix := x0; ax := x1 ELSE ix := x1; ax := x0 END;
  566.   IF y0 > y1 THEN iy := y0; ay := y1 ELSE iy := y1; ay := y0 END;
  567.   IF ax < b.update[0] THEN b.update[0] := ax END;
  568.   IF ay < b.update[1] THEN b.update[1] := ay END;
  569.   IF ix > b.update[2] THEN b.update[2] := ix END;
  570.   IF iy > b.update[3] THEN b.update[3] := iy END;
  571.  
  572.   (* Linie zeichnen *)
  573.   collision := NoHit;
  574.   dx := x1 - x0; dy := y1 - y0;
  575.   ax := 0; ay := 0; ix := 1; iy := 1;
  576.   IF dx < 0 THEN dx := -dx; ix := -1 END;
  577.   IF dy < 0 THEN dy := -dy; iy := -1 END;
  578.   IF dx < dy THEN
  579.     ct := dx; dx := dy; dy := ct; ay := ix; ax := iy; ix := 0; iy := 0;
  580.   END;
  581.   of := dx DIV 2; ct := 0;
  582.  
  583.   WHILE (dx >= ct) DO
  584.     xbit := 31 - x0 MOD 32;
  585.     xset := b.widthSet * y0 + x0 DIV 32;
  586.     IF xbit IN b.mem[xset] THEN
  587.       EXCL(b.mem[xset], xbit);
  588.     ELSE
  589.       INCL(b.mem[xset], xbit);
  590.       IF xbit IN b.col[xset] THEN
  591.         collision := HitBackground;
  592.       END;
  593.     END;
  594.     INC(x0, ix); INC(y0, ax); INC (of, dy);
  595.     IF of >= dx THEN
  596.       DEC (of, dx); INC(x0, ay); INC(y0, iy);
  597.     END;
  598.     INC(ct);
  599.   END;
  600.   RETURN collision;
  601. END Line;
  602.  
  603. PROCEDURE (b : Bitmap) BackLine (x0, y0, x1, y1 : INTEGER);
  604. (* zeichnet eine Linie auf die Bitmap und den Hintergrund *)
  605. VAR dx, dy, ix, iy, ax, ay, ct, of, xbit, xset : INTEGER;
  606. BEGIN
  607.   IF (x0 < 0) OR (y0 < 0) OR (x1 < 0) OR (y1 < 0) THEN RETURN END;
  608.   IF (x0 >= b.width) OR (x1 >= b.width) OR
  609.      (y0 >= b.height) OR (y1 >= b.height) THEN RETURN END;
  610.  
  611.   (* Update Rechteck aktualisieren *)
  612.   IF x0 > x1 THEN ix := x0; ax := x1 ELSE ix := x1; ax := x0 END;
  613.   IF y0 > y1 THEN iy := y0; ay := y1 ELSE iy := y1; ay := y0 END;
  614.   IF ax < b.update[0] THEN b.update[0] := ax END;
  615.   IF ay < b.update[1] THEN b.update[1] := ay END;
  616.   IF ix > b.update[2] THEN b.update[2] := ix END;
  617.   IF iy > b.update[3] THEN b.update[3] := iy END;
  618.  
  619.   (* Linie zeichnen *)
  620.   dx := x1 - x0; dy := y1 - y0;
  621.   ax := 0; ay := 0; ix := 1; iy := 1;
  622.   IF dx < 0 THEN dx := -dx; ix := -1 END;
  623.   IF dy < 0 THEN dy := -dy; iy := -1 END;
  624.   IF dx < dy THEN
  625.     ct := dx; dx := dy; dy := ct; ay := ix; ax := iy; ix := 0; iy := 0;
  626.   END;
  627.   of := dx DIV 2; ct := 0;
  628.  
  629.   WHILE (dx >= ct) DO
  630.     xbit := 31 - x0 MOD 32;
  631.     xset := b.widthSet * y0 + x0 DIV 32;
  632.     INCL(b.mem[xset], xbit);
  633.     INCL(b.col[xset], xbit);
  634.     INC(x0, ix); INC(y0, ax); INC (of, dy);
  635.     IF of >= dx THEN
  636.       DEC (of, dx); INC(x0, ay); INC(y0, iy);
  637.     END;
  638.     INC(ct);
  639.   END;
  640. END BackLine;
  641.  
  642. PROCEDURE (b : Bitmap) Fill (); 
  643. VAR Erster, Farbe, Punkt : BOOLEAN; x, y, dummy : INTEGER;
  644. BEGIN
  645.   RETURN;
  646.  
  647.   Erster := TRUE;
  648.   FOR x := 0 TO b.width-1 DO
  649.     Farbe := TRUE;
  650.     FOR y := 0 TO b.height-1 DO
  651.       Punkt := b.GetPoint(x, y);
  652.       IF Punkt THEN
  653.         IF Erster THEN
  654.           Erster := FALSE;
  655.           Farbe := ~Farbe;
  656.         END;
  657.       ELSE
  658.         Erster := TRUE;
  659.         IF Farbe THEN
  660.           dummy := b.Point(x, y);
  661.         END;
  662.       END;
  663.     END;
  664.   END;
  665. END Fill;
  666.  
  667.  
  668. PROCEDURE (b : Bitmap) Rectangle (x, y, w, h : INTEGER);
  669. VAR i, j, xb, yb : INTEGER;
  670. BEGIN
  671.   FOR i := x TO x + w - 1 DO
  672.     FOR j := y TO y + h - 1 DO
  673.       yb := x DIV 32 + y * b.widthSet;
  674.       xb := 31 - x MOD 32;
  675.       INCL(b.mem[yb], xb);
  676.       INCL(b.col[yb], xb);
  677.     END;
  678.   END;
  679. END Rectangle;
  680.  
  681.  
  682. PROCEDURE Overlap(VAR r, p : VR.pxyarray) : BOOLEAN;
  683. BEGIN
  684.   IF r[0] < p[0] THEN r[0] := p[0] END;
  685.   IF r[1] < p[1] THEN r[1] := p[1] END;
  686.   IF r[2] > p[2] THEN r[2] := p[2] END;
  687.   IF r[3] > p[3] THEN r[3] := p[3] END;
  688.   RETURN (r[2] - r[0] >= 0) & (r[3] - r[1] >= 0);
  689. END Overlap;
  690.  
  691. PROCEDURE (b : Bitmap) Update(x, y : INTEGER);
  692. VAR w, h : INTEGER; visold : VR.pxyarray;
  693. BEGIN
  694.   IF b.update[2] < 0 THEN RETURN END; (* Nichts zum Updaten *)
  695.  
  696. (*
  697.   b.update[0] := b.update[0] DIV 16 * 16;
  698.   b.update[2] := b.update[2] DIV 16 * 16 + 15;
  699. *)
  700.  
  701.   (* Bildausschnitt verschieben ? *)
  702.   IF (x >= 0) & (y >= 0) THEN
  703.     w := b.visible[2] - b.visible[0]; h := b.visible[3] - b.visible[1];
  704.     visold := b.visible;
  705.     IF x < b.visible[0] + b.RandX THEN
  706.       b.visible[0] := x - b.RandX * 5 DIV 2;
  707.       IF b.visible[0] < 0 THEN b.visible[0] := 0 END;
  708.       IF b.visible[0] # visold[0] THEN
  709.         b.visible[2] := b.visible[0] + w;
  710.         b.update := b.visible
  711.       END;
  712.     ELSIF x > b.visible[2] - b.RandX THEN
  713.       b.visible[2] := x + b.RandX * 5 DIV 2;
  714.       IF b.visible[2] >= b.width THEN b.visible[2] := b.width - 1 END;
  715.       IF b.visible[2] # visold[2] THEN
  716.         b.visible[0] := b.visible[2] - w;
  717.         b.update := b.visible;
  718.       END;
  719.     END;
  720.     IF y < b.visible[1] + b.RandY THEN
  721.       b.visible[1] := y - b.RandY * 5 DIV 2;
  722.       IF b.visible[1] < 0 THEN b.visible[1] := 0 END;
  723.       IF b.visible[1] # visold[1] THEN
  724.         b.visible[3] := b.visible[1] + h;
  725.         b.update := b.visible;
  726.       END;
  727.     ELSIF y > b.visible[3] - b.RandY THEN
  728.       b.visible[3] := y + b.RandY * 5 DIV 2;
  729.       IF b.visible[3] >= b.height THEN b.visible[3] := b.height - 1 END;
  730.       IF b.visible[3] # visold[3] THEN
  731.         b.visible[1] := b.visible[3] - h;
  732.         b.update := b.visible;
  733.       END;
  734.     END;
  735.   END;
  736.  
  737.   IF Overlap(b.update, b.visible) THEN
  738.  
  739.     b.update[4] := b.update[0] - b.visible[0] + win.x;
  740.     b.update[5] := b.update[1] - b.visible[1] + win.y;
  741.     b.update[6] := b.update[2] - b.visible[0] + win.x;
  742.     b.update[7] := b.update[3] - b.visible[1] + win.y;
  743.  
  744.     IF Color THEN
  745.       VR.VrtCpyfm(Station, 1, b.update, b.mfdb, Screen, 0, 1);
  746.     ELSE
  747.       VR.VroCpyfm(Station, 3, b.update, b.mfdb, Screen);
  748.     END;
  749.  
  750.   END;
  751.  
  752.   b.update[0] := b.width;
  753.   b.update[1] := b.height;
  754.   b.update[2] := -1;
  755.   b.update[3] := -1;
  756.  
  757. END Update;
  758.  
  759. (* Point ****************************************************************)
  760.  
  761. PROCEDURE (p : Point) Init (x, y, vx, vy : LONGINT);
  762. BEGIN
  763.   p.x := x; p.y := y; p.vx := vx; p.vy := vy;
  764.   p.sx := -1; p.sy := -1; p.hit := NoHit;
  765. END Init;
  766.  
  767. PROCEDURE (p : Point) Move (dummy1, dummy2 : LONGINT);
  768. BEGIN
  769.   INC(p.x, p.vx * dt DIV fixcomma);
  770.   INC(p.y, p.vy * dt DIV fixcomma);
  771. END Move;
  772.  
  773. PROCEDURE (p : Point) Draw (Neu : BOOLEAN);
  774. BEGIN
  775.   p.hit := VScreen.Point(p.sx, p.sy);
  776.   IF Neu THEN
  777.     p.sx := SHORT(p.x DIV fixcomma);
  778.     p.sy := SHORT(p.y DIV fixcomma);
  779.     p.hit := VScreen.Point(p.sx, p.sy);
  780.   END;
  781. END Draw;
  782.  
  783. PROCEDURE (p : Point) Do() : BOOLEAN;
  784. VAR exp : Explosion;
  785.  
  786. BEGIN
  787.   IF p.hit = HitShip THEN
  788.     p.Draw(FALSE); (* löschen *);
  789.     DEC(HitCount);
  790.     RETURN TRUE;
  791.   ELSE
  792.     p.Move(0, 0); p.Draw(TRUE); (* setzt p.hit *)
  793.     IF p.hit = HitShip THEN
  794.       INC(HitCount);
  795.     END;
  796.   END;
  797.   RETURN p.hit = HitBackground;
  798. END Do;
  799.  
  800.  
  801. (* Ball *****************************************************************)
  802.  
  803. PROCEDURE (b : Ball) Init(x, y, vx, vy : LONGINT);
  804. BEGIN
  805.   b.Init^(x, y, vx, vy);
  806.  
  807.   b.loading := FALSE; b.bx := -1; b.by := -1;
  808.   NEW(b.shape); b.shape.Init(19, 19);
  809.   b.shape.Circle (9, 9, 8);
  810.  
  811.   b.Draw (TRUE);
  812. END Init;
  813.  
  814. PROCEDURE (b : Ball) Draw(Neu : BOOLEAN);
  815. BEGIN
  816.   b.hit := VScreen.Sprite(b.sx - 9, b.sy - 9, b.shape);
  817.   IF Neu THEN
  818.     b.sx := SHORT(b.x DIV fixcomma);
  819.     b.sy := SHORT(b.y DIV fixcomma);
  820.     b.hit := VScreen.Sprite(b.sx - 9, b.sy - 9, b.shape);
  821.   END;
  822. END Draw;
  823.  
  824. PROCEDURE (b : Ball) Do () : BOOLEAN;
  825. VAR dx, dy, v, beta, alpha, vs : LONGINT; vx2, vy2 : REAL; i : INTEGER;
  826. BEGIN
  827.   dx := LONG(myShip.sx + 10 - b.sx); dy := LONG(myShip.sy + 10 - b.sy);
  828.   IF b.loading THEN
  829.     i := VScreen.Line (b.sx, b.sy, b.bx, b.by);
  830.   END;
  831.   IF dx * dx + dy * dy < abstand2 THEN
  832.     b.bx := myShip.sx + 10; b.by := myShip.sy + 10;
  833.     i := VScreen.Line (b.sx, b.sy, b.bx, b.by);
  834.     b.loading := TRUE;
  835.   ELSIF b.loading THEN (* Abflug ... *)
  836.     (* Kugel und Schiff löschen *)
  837.     b.Draw(FALSE); (* löschen *)
  838.     myShip.Draw(FALSE);
  839.  
  840.     NEW(myLoadedShip);
  841.  
  842.     vx2 := myShip.vx * myShip.vx / fixcomma / fixcomma;
  843.     vy2 := myShip.vy * myShip.vy / fixcomma / fixcomma;
  844.     v := ENTIER(Math.sqrt(vx2 + vy2) * fixcomma);
  845.  
  846.     beta  := ENTIER(Math.arctan2 (myShip.vy, myShip.vx) * radtodeg);
  847.     alpha := ENTIER(Math.arctan2 (dy, dx) * radtodeg);
  848.     vs := v * sin[(beta - alpha + nangle) MOD nangle] DIV fixcomma;
  849.  
  850.     (* Impulserhaltung *)
  851.     myLoadedShip.Init(b.x + dx DIV gesamtmasse * fixcomma,
  852.                       b.y + dy DIV gesamtmasse * fixcomma,
  853.                       myShip.vx DIV gesamtmasse,
  854.                       myShip.vy DIV gesamtmasse);
  855.     myLoadedShip.beta := myShip.beta;
  856.  
  857.     myLoadedShip.alpha := alpha * fixcomma;
  858.  
  859.     (* Drallerhaltung *)
  860.     myLoadedShip.valpha := LONG(radtodeg) * LONG(traegschiff) DIV
  861.                            LONG(traeggesamt) * vs DIV LONG(distschiff);
  862.  
  863.     b.loading := FALSE;
  864.     objects.Remove(myShip);
  865.     objects.Insert(myLoadedShip);
  866.  
  867.     myShip := myLoadedShip;
  868.     RETURN TRUE;
  869.   END;
  870.   RETURN FALSE;
  871. END Do;
  872.  
  873.  
  874.  
  875. (* Defender *************************************************************)
  876.  
  877. PROCEDURE (d : Defender) Init(x, y, vx, vy : LONGINT);
  878. VAR b : BOOLEAN;
  879. BEGIN
  880.   d.Init^(x, y, vx, vy);
  881.   
  882.   d.LastShoot := 0; d.ShootFreq := 100000;
  883.   d.Range := 200 * 2 * fixcomma;
  884.  
  885.   NEW(d.shape); d.shape.Init(32, 32);
  886.   d.shape.Circle(15, 15, 10);
  887.   d.shape.Line(1, 15, 29, 15);
  888.   d.shape.Line(15, 1, 15, 29);
  889.   d.Draw(TRUE);
  890. END Init;
  891.  
  892. PROCEDURE (d : Defender) Draw (Neu : BOOLEAN);
  893. BEGIN
  894.   d.hit := VScreen.Sprite(d.sx-15, d.sy-15, d.shape);
  895.   IF Neu THEN
  896.     d.sx := SHORT(d.x DIV fixcomma);
  897.     d.sy := SHORT(d.y DIV fixcomma);
  898.     d.hit := VScreen.Sprite(d.sx-15, d.sy-15, d.shape);
  899.  
  900.  
  901.   END;
  902. END Draw;
  903.  
  904. PROCEDURE (d : Defender) Do () : BOOLEAN;
  905.  
  906. VAR dx, dy, vx, vy, beta : LONGINT;
  907.     bullet : Point;
  908. BEGIN
  909.   IF HitCount > 0 THEN
  910.     d.Draw(TRUE);
  911.     IF d.hit = HitShip THEN
  912.       d.Draw(FALSE); (* löschen *)
  913.       RETURN TRUE;
  914.     END;
  915.   END;
  916.   
  917.   IF (d.LastShoot <= 0) THEN
  918.     dx := myShip.x - d.x;
  919.     dy := myShip.y - d.y;
  920.     beta  := ENTIER(Math.arctan2 (dy, dx) * radtodeg);
  921.  
  922.     IF ABS(dx) + ABS(dy) < d.Range THEN
  923.       vx := 15 * cos[(beta + nangle) MOD nangle];
  924.       vy := 15 * sin[(beta + nangle) MOD nangle];
  925.  
  926.       NEW(bullet);
  927.       bullet.Init(d.x + vx, d.y + vy, vx DIV 16 + d.vx, vy DIV 16 + d.vy);
  928.       objects.Insert(bullet);
  929.     END;
  930.     
  931.     d.LastShoot := d.ShootFreq + 4 * (XBIOS.Random() MOD d.ShootFreq);
  932.   END;
  933.   IF d.LastShoot > 0 THEN
  934.     DEC(d.LastShoot, dt);
  935.   END;
  936.   RETURN FALSE;
  937. END Do;
  938.  
  939.  
  940. (* Explosion ************************************************************)
  941.  
  942. PROCEDURE (e : Explosion) Init (x, y, vx, vy : LONGINT);
  943. BEGIN
  944.   e.Init^(x, y, vx, vy);
  945.   NEW(e.shape); e.shape.Init(32, 32);
  946. END Init;
  947.  
  948. PROCEDURE (e : Explosion) Do() : BOOLEAN;
  949. VAR i, j, x, y : INTEGER; newshape : ARRAY 32 OF SET;
  950. BEGIN
  951.   IF e.LastShape < 0 THEN
  952.     e.hit := VScreen.Sprite(e.sx, e.sy, e.shape);
  953.     e.sx := SHORT(e.x DIV fixcomma)-15; e.sy := SHORT(e.y DIV fixcomma)-15;
  954.  
  955.     FOR j := 0 TO 31 DO
  956.       newshape[j] := {};
  957.     END;
  958.     FOR i := 0 TO 31 DO
  959.       FOR j := 0 TO 31 DO
  960.         IF i IN e.shape.shape[j] THEN
  961. (*
  962.           x := i + Rnd(3) - 1;
  963.           y := j + Rnd(3) - 1;
  964. *)
  965.           IF (x >= 0) AND (y >= 0) AND (x < 32) AND (y < 32) THEN
  966.             INCL(newshape[y], x);
  967.           END;
  968.         END;
  969.       END;
  970.     END;
  971.     FOR j := 0 TO 31 DO
  972.       e.shape.shape[j] := newshape[j];
  973.     END;
  974.     e.hit := VScreen.Sprite(e.sx, e.sy, e.shape);
  975.     e.LastShape := 10000;
  976.   ELSE
  977.     DEC(e.LastShape, dt);
  978.   END;
  979.   RETURN FALSE;
  980. END Do;
  981.  
  982.  
  983.  
  984. (* Schiff ***************************************************************)
  985.  
  986. PROCEDURE (s : Ship) Init(x, y, vx, vy : LONGINT);
  987. VAR ax, ay, bx, by, cx, cy, i : INTEGER;
  988.     co, si : LONGINT;
  989. BEGIN
  990.   s.Init^(x, y, vx, vy);
  991.   
  992.   s.beta := 271 * fixcomma;
  993.   s.sb := SHORT(s.beta DIV fixcomma DIV 4);
  994.   
  995.   FOR i := 0 TO 89 DO
  996.     NEW(s.shape[i]); s.shape[i].Init(21, 20);
  997.     co := cos[4 * i]; si := sin[4 * i];
  998.     ax := SHORT((-7 * co - 7 * si) DIV fixcomma) + 10;
  999.     ay := SHORT((-7 * si + 7 * co) DIV fixcomma) + 10;
  1000.     bx := SHORT((10 * co) DIV fixcomma) + 10;
  1001.     by := SHORT((10 * si) DIV fixcomma) + 10;
  1002.     cx := SHORT((-7 * co + 7 * si) DIV fixcomma) + 10;
  1003.     cy := SHORT((-7 * si - 7 * co) DIV fixcomma) + 10;
  1004.     s.shape[i].Line (ax, ay, bx, by);
  1005.     s.shape[i].Line (bx, by, cx, cy);
  1006.     s.shape[i].Line (cx, cy, ax, ay);
  1007.     NEW(s.shapet[i]); s.shapet[i].Init(21, 21);
  1008.     s.shapet[i].shape := s.shape[i].shape;
  1009.     ax := SHORT((-7 * co - 4 * si) DIV fixcomma) + 10;
  1010.     ay := SHORT((-7 * si + 4 * co) DIV fixcomma) + 10;
  1011.     bx := SHORT((-10 * co) DIV fixcomma) + 10;
  1012.     by := SHORT((-10 * si) DIV fixcomma) + 10;
  1013.     cx := SHORT((-7 * co + 4 * si) DIV fixcomma) + 10;
  1014.     cy := SHORT((-7 * si - 4 * co) DIV fixcomma) + 10;
  1015.     s.shapet[i].Line (ax, ay, bx, by);
  1016.     s.shapet[i].Line (bx, by, cx, cy);
  1017.  
  1018.   END;
  1019.   s.thrust := FALSE; s.last := FALSE;
  1020.   s.LastShoot := 0; s.ShootFreq := 100000;
  1021. END Init;
  1022.  
  1023. PROCEDURE(s : Ship) Draw (Neu : BOOLEAN);
  1024. BEGIN
  1025.   IF s.last THEN
  1026.     s.hit := VScreen.Sprite(s.sx, s.sy, s.shapet[s.sb]);
  1027.   ELSE
  1028.     s.hit := VScreen.Sprite(s.sx, s.sy, s.shape[s.sb]);
  1029.   END;
  1030.   IF Neu THEN
  1031.     s.last := s.thrust;
  1032.     s.sx := SHORT(s.x DIV fixcomma) - 10;
  1033.     s.sy := SHORT(s.y DIV fixcomma) - 10;
  1034.     s.sb := SHORT(s.beta DIV fixcomma DIV 4);
  1035.     IF s.last THEN
  1036.       s.hit := VScreen.Sprite(s.sx, s.sy, s.shapet[s.sb]);
  1037.     ELSE
  1038.       s.hit := VScreen.Sprite(s.sx, s.sy, s.shape[s.sb]);
  1039.     END;
  1040.   END;
  1041. END Draw;
  1042.  
  1043. PROCEDURE(s : Ship) Move (acc, angle : LONGINT);
  1044. BEGIN
  1045.   INC(s.vx, cos[angle DIV fixcomma] * acc DIV fixcomma);
  1046.   INC(s.vy, sin[angle DIV fixcomma] * acc DIV fixcomma + GravStep);
  1047.   INC(s.x, s.vx * dt DIV fixcomma);
  1048.   INC(s.y, s.vy * dt DIV fixcomma);
  1049. END Move;
  1050.  
  1051. PROCEDURE(s : Ship) Do () : BOOLEAN;
  1052. VAR mb, Shifts : SET;
  1053.     mx, my, i : INTEGER;
  1054.     acc, bx, by : LONGINT;
  1055.     Shoot : Point;
  1056.     Shift : SET; Scan : INTEGER; Ascii : CHAR;
  1057. BEGIN
  1058.   Evnt.MKstate(mx, my, mb, Shifts);
  1059.   IF Evnt.LSHIFT IN Shifts THEN
  1060.     s.beta := (s.beta + nangle2 - BetaStep) MOD nangle2;
  1061.   END;
  1062.   IF Evnt.ALTERNATE IN Shifts THEN
  1063.     s.beta := (s.beta + BetaStep) MOD nangle2;
  1064.   END;
  1065.   IF Evnt.RSHIFT IN Shifts THEN
  1066.     acc := AccStep; s.thrust := TRUE;
  1067.   ELSE
  1068.     acc := 0; s.thrust := FALSE;
  1069.   END;
  1070.  
  1071.   IF (Evnt.CONTROL IN Shifts) AND (s.LastShoot <= 0) THEN
  1072.     bx := 11 * cos[s.beta DIV fixcomma];
  1073.     by := 11 * sin[s.beta DIV fixcomma];
  1074.     NEW(Shoot);
  1075.     IF s IS LoadedShip THEN
  1076.       Shoot.Init(LONG(s(LoadedShip).mx) * fixcomma + bx,
  1077.                  LONG(s(LoadedShip).my) * fixcomma + by,
  1078.                  bx DIV 5 + s.vx, by DIV 5 + s.vy);
  1079.     ELSE
  1080.       Shoot.Init(s.x + bx, s.y + by, bx DIV 5 + s.vx, by DIV 5 + s.vy);
  1081.     END;
  1082.     objects.Add(Shoot); INC(nobj);
  1083.     s.LastShoot := s.ShootFreq;
  1084.   END;
  1085.  
  1086.   IF s.LastShoot > 0 THEN
  1087.     DEC(s.LastShoot, dt)
  1088.   END;
  1089.  
  1090.   s.Move(acc, s.beta); s.Draw(TRUE);
  1091.  
  1092.   IF s.hit = HitBackground THEN (* rummms... *)
  1093.     s.vx := 0; s.vy := 0;
  1094.     IF s IS LoadedShip THEN
  1095.       s(LoadedShip).valpha := 0;
  1096.     END;
  1097.   ELSIF s.hit = HitExit THEN
  1098.     ende := HitExit;
  1099.   ELSIF (HitCount > 0) AND (s.hit = HitShip) THEN (* bummms... *)
  1100.     s.Draw(FALSE); (* löschen *)
  1101.     ende := HitShip;
  1102.     RETURN TRUE;
  1103.   END;
  1104.   RETURN FALSE;
  1105. END Do;
  1106.  
  1107. (* Schiff mit Kugel *****************************************************)
  1108.  
  1109. PROCEDURE(l : LoadedShip) Init (x, y, vx, vy : LONGINT);
  1110. BEGIN
  1111.   l.Init^(x, y, vx, vy);
  1112.   l.alpha := 0; l.valpha := 0;
  1113.   l.mx := -1; l.my := -1; l.lx := -1; l.ly := -1;
  1114.  
  1115.   l.valphaconst := LONG(radtodeg) * LONG(distschiff) * LONG(fixcomma) DIV
  1116.                    LONG(traeggesamt);
  1117.  
  1118.   NEW(l.ball); l.ball.Init(19, 19);
  1119.   l.ball.Circle (9, 9, 8);
  1120. END Init;
  1121.  
  1122. PROCEDURE(l : LoadedShip) Move (acc, angle : LONGINT);
  1123. VAR da : LONGINT; (* Winkeldifferenz *)
  1124. BEGIN
  1125.  
  1126.   da := (angle - l.alpha + nangle2) MOD nangle2 DIV fixcomma;
  1127.  
  1128.   (* Verschiebung *)
  1129.   l.Move^(acc DIV (ballmasse + 1), angle);
  1130.  
  1131.   (* Drehbewegung *)
  1132.   INC(l.valpha, acc * sin[da] DIV fixcomma * l.valphaconst DIV fixcomma);
  1133.   l.alpha := (l.alpha + l.valpha * dt DIV fixcomma + nangle2) MOD nangle2;
  1134.  
  1135. END Move;
  1136.  
  1137. PROCEDURE(l : LoadedShip) Draw (Neu : BOOLEAN);
  1138. VAR a, hit : INTEGER;
  1139. BEGIN
  1140.   l.hit := VScreen.Line(l.mx, l.my, l.lx, l.ly);
  1141.  
  1142.   l.hit := VScreen.Sprite(l.lx - 9, l.ly - 9, l.ball);
  1143.  
  1144.   IF l.last THEN
  1145.     l.hit := VScreen.Sprite(l.sx, l.sy, l.shapet[l.sb]);
  1146.   ELSE
  1147.     l.hit := VScreen.Sprite(l.sx, l.sy, l.shape[l.sb]);
  1148.   END;
  1149.  
  1150.   IF Neu THEN
  1151.     a := SHORT(l.alpha DIV fixcomma);
  1152.     l.mx := SHORT((l.x + distschiff * cos[a]) DIV fixcomma);
  1153.     l.my := SHORT((l.y + distschiff * sin[a]) DIV fixcomma);
  1154.     l.lx := SHORT((l.x - distball * cos[a]) DIV fixcomma);
  1155.     l.ly := SHORT((l.y - distball * sin[a]) DIV fixcomma);
  1156.   
  1157.     l.last := l.thrust;
  1158.     l.sx := l.mx - 10;
  1159.     l.sy := l.my - 10;
  1160.     l.sb := SHORT(l.beta DIV fixcomma DIV 4);
  1161.  
  1162.     IF l.last THEN
  1163.       l.hit := VScreen.Sprite(l.sx, l.sy, l.shapet[l.sb]);
  1164.     ELSE
  1165.       l.hit := VScreen.Sprite(l.sx, l.sy, l.shape[l.sb]);
  1166.     END;
  1167.  
  1168.     hit := VScreen.Sprite(l.lx - 9, l.ly - 9, l.ball);
  1169.     IF hit > l.hit THEN l.hit := hit END;
  1170.   
  1171.     hit := VScreen.Line(l.mx, l.my, l.lx, l.ly);
  1172.   END;
  1173. END Draw;
  1174.  
  1175. (* Los geht's ***********************************************************)
  1176.  
  1177. PROCEDURE Run;
  1178. VAR Workin  : VC.workin;
  1179. BEGIN
  1180.   InitTables();
  1181.  
  1182.   Graf.ChangeMouse( Graf.ARROW);
  1183.   Station := 1; (* VDI Virtual Workstation öffnen *)
  1184.   Workin.Id := 1; Workin.LineType := 1;
  1185.   Workin.LineColor := 1; Workin.MarkType := 1;
  1186.   Workin.MarkColor := 1; Workin.Font := 1;
  1187.   Workin.TextColor := 1; Workin.FillStyle := 0;
  1188.   Workin.FillPat := 0; Workin.FillColor := 1;
  1189.   Workin.KoorType := 2;
  1190.   VC.VOpnvwk(Workin, Station, Workout);
  1191.   VA.VswrMode(Station,VA.EXOR);
  1192.   VA.VsfPerimeter(Station, FALSE);
  1193.  
  1194.   Color := ~(Workout.NumColor = 2);
  1195.  
  1196.   IF ~Rsrc.Load("THRUSTN.RSC") THEN
  1197.     Task.Exit(0);
  1198.   END;
  1199.   NEW(menu); menu.Init(Rsrc.GetAddr( MENU ));
  1200.   menu.Set(SPIEL, START, Spiel);
  1201.   menu.Set(SPIEL, ENDE, Ende);
  1202.   menu.Set(THRUST, INFO, Info);
  1203.   menu.Show;
  1204.   
  1205.   NEW(InfoDialog); InfoDialog.InitDialog (Rsrc.GetAddr(ABOUT), 0, TRUE);
  1206.   InfoDialog.SetTitle ("Thrust Info");
  1207.  
  1208.   NEW(win); win.Initialize;
  1209.   win.SetTitle(WindowTitle);
  1210.  
  1211.   Graf.ChangeMouse( Graf.BEE);
  1212.   NEW(myLevel); myLevel.Init();
  1213.   Graf.ChangeMouse( Graf.ARROW);
  1214.  
  1215.   win.SetDataWH (VScreen.width, VScreen.height);
  1216.   IF VScreen.width < win.w THEN
  1217.     win.w := VScreen.width;
  1218.     win.fw := win.w;
  1219.   END;
  1220.   IF VScreen.height < win.h THEN
  1221.     win.h := VScreen.height;
  1222.     win.fh := win.h;
  1223.   END;
  1224.   
  1225.   win.SetInfo(" L-SHIFT/ALTERNATE = Rotation, R-SHIFT = Thrust, CONTROL = Fire, ESC = Ende");
  1226.   win.Open;
  1227.  
  1228.   GemApp.Run;
  1229. END Run;
  1230.  
  1231.  
  1232. PROCEDURE (v : myViewer) Redraw (x, y, w, h : INTEGER);
  1233. VAR Off : LONGINT; update : BOOLEAN;
  1234.     icon : Objc.ptr; ix, iy, iw, ih : INTEGER;
  1235. BEGIN
  1236.   IF v.iconified THEN
  1237.     v.Redraw^(x, y, w, h); (* löschen *);
  1238.     icon := Objc.GetPtr(Rsrc.GetAddr(BILD), 0);
  1239.     Wind.GetXYWH(v.handle, Wind.WORK, ix, iy, iw, ih);
  1240.     icon.X := ix + (iw - icon.W) DIV 2;
  1241.     icon.Y := iy + (ih - icon.H) DIV 2;
  1242.     Objc.Draw(icon, 0, 100, x, y, w, h);
  1243.   ELSE
  1244.     (* Offset Kontrolle *)
  1245.     update := FALSE;
  1246.     IF (v.xOff + v.w > v.dw) & (v.xOff > 0) THEN
  1247.       Off := SHORT(v.dw) - v.w;
  1248.       IF Off < 0 THEN Off := 0 END;
  1249.       v.SetOffset (Off, v.yOff);
  1250.       update := TRUE;
  1251.     END;
  1252.     IF (v.yOff + v.h > v.dh) & (v.yOff > 0) THEN
  1253.       Off := SHORT(v.dh) - v.h;
  1254.       IF Off < 0 THEN Off := 0 END;
  1255.       v.SetOffset (v.xOff, Off);
  1256.       update := TRUE;
  1257.     END;
  1258.   
  1259.     IF update THEN
  1260.       v.RedrawAll;
  1261.       RETURN;
  1262.     END;
  1263.   
  1264.     VScreen.update[0] := SHORT(v.xOff) + x - v.x; (* Updatebereich *)
  1265.     VScreen.update[1] := SHORT(v.yOff) + y - v.y;
  1266.     VScreen.update[2] := VScreen.update[0] + w - 1;
  1267.     VScreen.update[3] := VScreen.update[1] + h - 1;
  1268.   
  1269.     VScreen.visible[0] := SHORT(v.xOff); (* gesamtes Fenster *)
  1270.     VScreen.visible[1] := SHORT(v.yOff);
  1271.     VScreen.visible[2] := SHORT(v.xOff) + v.w - 1;
  1272.     IF VScreen.visible[2] >= VScreen.width THEN
  1273.       VScreen.visible[2] := VScreen.width - 1
  1274.     END;
  1275.     VScreen.visible[3] := SHORT(v.yOff) + v.h - 1;
  1276.     IF VScreen.visible[3] >= VScreen.height THEN
  1277.       VScreen.visible[3] := VScreen.height - 1
  1278.     END;
  1279.   
  1280.     VScreen.Update(-1, -1);
  1281.   END;
  1282. END Redraw;
  1283.  
  1284.  
  1285. PROCEDURE Spiel();
  1286. VAR t0, t, c, t2 : LONGINT;
  1287.     obj : LinkedList.Element;
  1288.  
  1289.     handle : INTEGER;
  1290.     Shift : SET; Scan : INTEGER; Ascii : CHAR;
  1291.     aus, hilf : ARRAY 128 OF CHAR;
  1292.  
  1293.   PROCEDURE DoObject (obj : LinkedList.Element);
  1294.   BEGIN
  1295.     IF obj(Point).Do () THEN
  1296.       objects.Remove(obj);
  1297.       DEC(nobj);
  1298.     END;
  1299.     VScreen.Update(myShip.sx, myShip.sy);
  1300.   END DoObject;
  1301.  
  1302. BEGIN
  1303.   debug := TRUE;
  1304.   Gravitation := FALSE;
  1305.  
  1306.   IF win.iconified THEN
  1307.     win.UnIconified (0,0,0,0);
  1308.   END;
  1309.   win.Open;
  1310.  
  1311.     Graf.ChangeMouse( Graf.BEE);
  1312.     NEW(myLevel); myLevel.Init();
  1313.     Graf.ChangeMouse( Graf.ARROW);
  1314.     Graf.HideMouse();
  1315.  
  1316.     Wind.Update(Wind.BEGUPD);
  1317.  
  1318.     HitCount := 0;
  1319.     t := 0; c := 0;
  1320.     t := Timer.Get(); t0 := t;
  1321.     AccStep := 0; BetaStep := 0;
  1322.     ende := NoHit;
  1323.  
  1324.     REPEAT
  1325.  
  1326.       INC(c);
  1327. (*
  1328.       t2 := Timer.Get();
  1329.       dt := (t2 - t) * fixcomma DIV 2; t := t2;
  1330. *)
  1331.       t2 := Timer.Get();
  1332.       INC(dt, (t2 - t) * fixcomma DIV 32); t := t2;
  1333.       DEC(dt, dt DIV 16); (* Tiefpass *)
  1334.  
  1335.       AccStep := dt DIV 64;
  1336.       BetaStep := 2 * dt;
  1337.       IF Gravitation THEN
  1338.         GravStep := dt DIV 512;
  1339.       ELSE
  1340.         GravStep := 0;
  1341.       END;
  1342.  
  1343.       objects.Do (DoObject);
  1344.  
  1345.       IF IO.KeyPressed() THEN
  1346.         IO.ReadKey (Shift, Scan, Ascii);
  1347.         IF Ascii = CHR(27) THEN
  1348.           ende := HitEsc; (* ESC *)
  1349.         END;
  1350.         IF Ascii = "d" THEN debug := TRUE END;
  1351.       END;
  1352.  
  1353.     UNTIL ende # NoHit;
  1354.  
  1355.     t := Timer.Get() - t0;
  1356.  
  1357.     CASE ende OF
  1358.       HitEsc : aus := " ESCAPE! Zeit = ";
  1359.     | HitShip : aus := " HIT!  Zeit = ";
  1360.     | HitExit : aus := " EXIT! Zeit = ";
  1361.     END;
  1362.     NumStr.LCardTo (t DIV 200, 10, hilf); Strings.Append(hilf, aus);
  1363.     Strings.AppendC (".", aus);
  1364.     NumStr.LCardTo (t MOD 200 DIV 2, 10, hilf); Strings.Append(hilf, aus);
  1365.     Strings.Append (" s, ", aus);
  1366.     Strings.Append (" Zyklus = ", aus);
  1367.     NumStr.LCardTo (t DIV (c DIV 5), 10, hilf); Strings.Append(hilf, aus);
  1368.     Strings.Append (" ms", aus);
  1369.  
  1370.     Graf.ShowMouse();
  1371.     win.SetInfo(aus);
  1372.  
  1373.   Wind.Update(Wind.ENDUPD);
  1374.   win.SetOffset(VScreen.visible[0], VScreen.visible[1]);
  1375.  
  1376. END Spiel;
  1377.  
  1378. PROCEDURE Info;
  1379. BEGIN
  1380.   InfoDialog.Open;
  1381. END Info;
  1382.  
  1383. PROCEDURE Ende;
  1384. BEGIN
  1385.   win.Remove;
  1386.   GemApp.exit := TRUE;
  1387. END Ende;
  1388.  
  1389. BEGIN
  1390.   IF ~Sys.Loader THEN (* if running as stand alone program *)
  1391.     Run;
  1392.     Task.Exit(0); (* needed for clean up; will not return *)
  1393.   END;
  1394. END Thrust.
  1395.